﻿using Base.Api.Models;
using Base.Api.Repository;
using Base.Data.Entity;
using Common.AspNetCore;
using Common.RunModels.FCP;
using Common.RunModels.Login;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Base.Api.Service
{
    public class AuthLoginService : CommonService
    {
        private readonly AuthService authService;
        private readonly BaseRepository baseRepository;

        public AuthLoginService(IServiceProvider provider, AuthService auth, BaseRepository baseRep) : base(provider)
        {
            this.authService = auth;
            this.baseRepository = baseRep;
        }

        public async Task<LoginInfo> GetLoginInfoAsync(LoginInfoRequest request)
        {
            if (request == null || string.IsNullOrEmpty(request.MemberId))
            {
                return null;
            }

            var ret = new LoginInfo();
            MemberAuthModel memberAuthModel = null;
            int memberType = await this.authService.GetMemberRoleTypeAsync(request.MemberId, request.ClientType);
            memberAuthModel = await this.authService.GetMemberAuthAsync(request.MemberId, request.ClientType);
             
            ret.MemberRoleType = memberType;

            //// 菜单
            var menus = await this.GetLoginMenuAsync(request.OrgId, request.ClientType, request.Lang);
            if (menus.Any())
            {
                if (memberType == 0)
                {
                    var formIds = memberAuthModel != null ?
                        memberAuthModel.Roles.SelectMany(t => t.Forms).Select(t => t.FCPFormId).ToList() :
                             new List<string>();
                    menus = menus.Where(i => string.IsNullOrEmpty(i.FormId) || formIds.Contains(i.FormId)).ToList();
                }

                var fristLevel = menus.Where(i => string.IsNullOrEmpty(i.ParentId)).ToList();
                foreach (var f in fristLevel)
                {
                    var secLevel = menus.Where(i => i.ParentId == f.Id).ToList();
                    if (!secLevel.Any())
                    {
                        menus.Remove(f);
                        continue;
                    }

                    bool hasChild = false;
                    foreach (var s in secLevel)
                    {
                        if (!menus.Any(t => t.ParentId == s.Id))
                        {
                            menus.Remove(s);
                        }
                        else
                        {
                            hasChild = true;
                        }
                    }

                    if (!hasChild)
                    {
                        menus.Remove(f);
                    }
                }

                AddMenuTreeNode(menus, null, null, ret);
            }

            ////表单版本
            if (request.LastFormVersionTime != null)
            {
                var param = new FCPFormVersionParam() { OrgId = request.OrgId, Time = request.LastFormVersionTime };
                var removekeys = await this.CallService.PostListAsync<string>("FCP", "FCP/GetFormLastVersion", param);
                if (removekeys != null && removekeys.Any())
                {
                    ret.RemoveFormVersionKeys.AddRange(removekeys);
                }
            }

            ret.FormVersionTime = DateTime.Now;
            if (memberAuthModel != null && memberAuthModel.Roles != null && memberAuthModel.Roles.Any())
            {
                List<string> workstageIds = new List<string>();
                memberAuthModel.Roles.ForEach(t =>
                {
                    t.Forms.ForEach(t1 =>
                    {
                        var f = ret.AuthForms.FirstOrDefault(t2 => t2.FormId == t1.FCPFormId);
                        if (f == null)
                        {
                            f = new LoginAuthForm
                            {
                                FormId = t1.FCPFormId
                            };
                            ret.AuthForms.Add(f);
                        }

                        t1.Btns.ForEach(t3 =>
                        {
                            var b = f.Btns.FirstOrDefault(t2 => t2.BtnId == t3.BtnId);
                            if (b == null)
                            {
                                b = new LoginAuthFormBtn
                                {
                                    BtnId = t3.BtnId
                                };
                                f.Btns.Add(b);
                            }
                        });
                        t1.Fields.ForEach(t3 =>
                        {
                            var b = f.Fields.FirstOrDefault(t2 => t2.FieldId == t3.FieldId);
                            if (b == null)
                            {
                                b = new LoginAuthFormField
                                {
                                    FieldId = t3.FieldId
                                };
                                f.Fields.Add(b);
                            }
                        });
                    });

                    if (t.FilterOrgType == 1)
                    {
                        ret.RoleFiterOrgType = 1;
                    }
                    else if (t.FilterOrgType == 2 && ret.RoleFiterOrgType != 1)
                    {
                        ret.RoleFiterOrgType = 2;
                        ret.RoleOrgIds.AddRange(t.RoleOrgIds);
                    }
                });
            }

            ret.RoleOrgIds = ret.RoleOrgIds.Distinct().ToList();

            return ret;
        }

        public async Task<List<LoginMenu>> GetLoginMenuAsync(string orgId, int clientType, string lang)
        {
            var orgs = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_menu>(null, t => t.org_id == orgId && t.platform_type == clientType && t.enable_status == 0);
            var baseIds = orgs.Where(t => !string.IsNullOrEmpty(t.label_base_label_id)).Select(t => t.label_base_label_id).ToList();
            var baseLabelDetails = baseIds.Any() ? await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label_detail>(null, t => baseIds.Contains(t.base_label_id)) : null;
            List<LoginMenu> ret = new List<LoginMenu>();
            List<FCPForm> forms = null;
            var formIds = orgs.Where(t => !string.IsNullOrEmpty(t.fcp_form_id)).Select(t => t.fcp_form_id).ToList();
            if (formIds.Any())
            {
                forms = await GetAllFormByIdsAsync(formIds);
            }

            orgs.ForEach(t =>
            {
                var o = GetLibLoginMenu(t, forms, ret);
                var label = baseLabelDetails?.FirstOrDefault(t1 => t1.base_label_id == t.label_base_label_id && t1.lang == lang);
                if (label == null)
                {
                    label = baseLabelDetails?.Where(t1 => t1.base_label_id == t.label_base_label_id).OrderBy(t => t.lang).FirstOrDefault();
                }

                if (label != null)
                {
                    o.Label = label.label;
                }
            });

            List<LoginMenu> res = new List<LoginMenu>();
            ret?.ForEach(t =>
            {
                var st = new LoginMenu()
                {
                    FormCode = t.FormCode,
                    FormId = t.FormId,
                    FormName = t.FormName,
                    FormType = t.FormType,
                    MenuStyle = t.MenuStyle,
                    Id = t.Id,
                    Label = t.Label,
                    MenuIcon = t.MenuIcon,
                    MenuNum = t.MenuNum,
                    MenuParam = t.MenuParam,
                    ParentId = t.ParentId,
                    MenuPath = t.MenuPath,
                    IsDisabled = t.IsDisabled
                };
                if (t.CustomBtns != null)
                {
                    st.CustomBtns.AddRange(t.CustomBtns);
                }

                res.Add(st);
            });

            return res;
        }

        private async Task<List<FCPForm>> GetAllFormByIdsAsync(List<string> formIds)
        {
            var param = new FCPFormByIdParam() { Ids = formIds };
            return await this.CallService.PostListAsync<FCPForm>("FCP", "FCP/GetAllFormByIds", param);
        }

        private LoginMenu GetLibLoginMenu(t_menuBase menu, List<FCPForm> forms, List<LoginMenu> ret)
        {
            LoginMenu o = new LoginMenu()
            {
                Label = menu.label,
                Id = menu.id,
                ParentId = menu.parent_id,
                FormId = menu.fcp_form_id,
                MenuIcon = menu.menu_icon,
                MenuNum = menu.num,
                MenuParam = menu.menu_param,
                MenuStyle = menu.menu_style,
                IsDisabled = menu.is_disabled,
            };
            if (!string.IsNullOrEmpty(menu.fcp_form_id) && forms != null && forms.Any())
            {
                var f = forms.FirstOrDefault(t => t.Id == menu.fcp_form_id);
                if (f != null)
                {
                    o.FormCode = f.Code;
                    o.FormName = f.Name;
                    o.FormType = f.FormType;
                    o.MenuPath = f.FormPath;

                    f.CustomBtns?.ForEach(t3 =>
                    {
                        o.CustomBtns.Add(new LoginMenuCustomBtn()
                        {
                            ServiceCode = t3.ServiceCode,
                            Api = t3.Api,
                            BtnCode = t3.BtnCode,
                            BtnId = t3.BtnId,
                            BtnLabel = t3.BtnLabel,
                            IsAuth = t3.IsAuth,
                            IsVisible = t3.IsVisible,
                            Num = t3.Num,
                            BtnCss = t3.BtnCss,
                            BtnIcon = t3.BtnIcon,
                        });
                    });
                }
            }

            ret.Add(o);
            return o;
        }

        private void AddMenuTreeNode(List<LoginMenu> menus, string parentId, LoginMenuTreeNode parentNode, LoginInfo ret)
        {
            var tmps = menus.Where(t => t.ParentId == parentId).OrderBy(t => t.MenuNum).ToList();
            if (tmps == null || !tmps.Any())
            {
                return;
            }

            foreach (var item in tmps)
            {
                LoginMenuTreeNode cm = new LoginMenuTreeNode
                {
                    Menu = item,
                    Id = item.Id
                };
                if (parentNode != null)
                {
                    parentNode.Childrens.Add(cm);
                }
                else
                {
                    ret.Menus.Add(cm);
                }

                AddMenuTreeNode(menus, item.Id, cm, ret);
            }
        }
    }
}
